package com.mk.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mk.common.DeleteRequest;
import com.mk.exception.BusinessException;
import com.mk.exception.ErrorCode;
import com.mk.exception.ThrowUtils;
import com.mk.mapper.SpaceMapper;
import com.mk.model.dto.space.SpaceAddRequest;
import com.mk.model.dto.space.SpaceEditRequest;
import com.mk.model.dto.space.SpaceQueryRequest;
import com.mk.model.dto.space.SpaceUpdateRequest;
import com.mk.model.entity.Space;
import com.mk.model.entity.User;
import com.mk.model.enums.SpaceLevelEnum;
import com.mk.model.vo.space.SpaceVO;
import com.mk.model.vo.user.UserVO;
import com.mk.service.SpaceService;
import com.mk.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zkm
 * @description 针对表【space(空间)】的数据库操作Service实现
 * @createDate 2024-12-28 17:01:24
 */
@Service
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
        implements SpaceService {

    @Autowired
    private UserService userService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Override
    public Boolean deleteSpace(DeleteRequest deleteRequest, User loginUser) {
        Long id = deleteRequest.getId();
        // 检验
        this.checkIdAuthWithExists(id, loginUser);

        // 删除空间， 关联删除空间中的图片 TODO 原子操作  (清理COS对象)
/*        Boolean b = transactionTemplate.execute(status -> {
            LambdaQueryWrapper<Picture> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Picture::getSpaceId, id);
            pictureService.remove(wrapper);
            return this.removeById(id);
        });*/
        this.removeById(id);
        return true;
    }

    @Override
    public Long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
        String spaceName = spaceAddRequest.getSpaceName();
        if (StrUtil.isBlank(spaceName)) {
            spaceName = "默认名称";
        }
        ThrowUtils.throwIf(spaceName.length() > 20, ErrorCode.PARAMS_ERROR, "空间名称过长");

        // 创建空间，返回空间ID
        Space space = new Space();
        this.fillSpaceByLevel(space); // 填充空间的级别参数
        space.setSpaceName(spaceName);
        space.setUserId(loginUser.getId());

        String lock = String.valueOf(loginUser.getId()).intern();
        synchronized (lock){
            Boolean save = transactionTemplate.execute(status -> { // 一条DML语句可不加事务
                // 每个用户只能有一个空间
                boolean b = this.lambdaQuery()
                        .eq(Space::getUserId, loginUser.getId())
//                      .last("for update") // 不加锁的情况可以使用 读独占锁 （加悲观锁）
                        .exists();
                ThrowUtils.throwIf(b, ErrorCode.OPERATION_ERROR, "空间创建数量已达到上限");
                return this.save(space);
            });
            if (!save){
                throw new BusinessException(ErrorCode.OPERATION_ERROR);
            }
        }
        return Optional.ofNullable(space.getId()).orElse(-1L);
    }

    @Override
    public Long updateSpace(SpaceUpdateRequest updateRequest, User loginUser) {
        Long id = updateRequest.getId();
        this.checkIdAuthWithExists(id, loginUser);// 只有管理员才有权限

        Space space = new Space();
        BeanUtils.copyProperties(updateRequest, space);
        space.setUpdateTime(new Date());
        boolean b = this.updateById(space);
        ThrowUtils.throwIf(!b, ErrorCode.OPERATION_ERROR);
        return space.getId();
    }

    @Override
    public Boolean editSpace(SpaceEditRequest editRequest, User loginUser) {
        Long id = editRequest.getId();
        this.checkIdAuthWithExists(id, loginUser);
        String spaceName = editRequest.getSpaceName();
        ThrowUtils.throwIf(StrUtil.isBlank(spaceName), ErrorCode.PARAMS_ERROR, "空间名称不能为空");
        ThrowUtils.throwIf(spaceName.length() > 20, ErrorCode.PARAMS_ERROR, "空间名称过长");

        Space space = new Space();
        BeanUtils.copyProperties(editRequest, space);
        space.setEditTime(new Date());
        boolean b = this.updateById(space);
        ThrowUtils.throwIf(!b, ErrorCode.OPERATION_ERROR);
        return true;
    }

    @Override
    public SpaceVO getSpaceVOById(Long id) {
        ThrowUtils.throwIf(id < 0 || id == null, ErrorCode.PARAMS_ERROR);
        Space space = this.getById(id);
        ThrowUtils.throwIf(ObjUtil.isEmpty(space), ErrorCode.NOT_FOUND_ERROR);
        SpaceVO spaceVO = this.getSpaceVO(space);
        return spaceVO;
    }

    @Override
    public Page<SpaceVO> pageSpaceVO(SpaceQueryRequest queryRequest) {

        Page<Space> spacePage = new Page<>();
        QueryWrapper<Space> queryWrapper = getQueryWrapper(queryRequest);
        this.page(spacePage, queryWrapper);
        Page<SpaceVO> spaceVOPage = getSpaceVOPage(spacePage);

        return spaceVOPage;
    }

    @Override
    public SpaceVO getSpaceVO(Space space) {
        SpaceVO spaceVO = SpaceVO.objToVo(space);
        // 设置空间创建人封装信息
        Long userId = space.getUserId();
        User user = userService.getById(userId);
        UserVO userVO = UserVO.objToVO(user);
        spaceVO.setUserVO(userVO);
        return spaceVO;
    }

    @Override
    public Page<SpaceVO> getSpaceVOPage(Page<Space> spacePage) {
        List<Space> spaceList = spacePage.getRecords();
        Page<SpaceVO> spaceVOPage = new Page<>(spacePage.getCurrent(), spacePage.getSize(), spacePage.getTotal());
        if (CollUtil.isEmpty(spaceList)) {
            return spaceVOPage;
        }
        // 对象列表 => 封装对象列表
        List<SpaceVO> spaceVOList = spaceList.stream().map(SpaceVO::objToVo).collect(Collectors.toList());
        // 1. 关联查询用户信息
        Set<Long> userIdSet = spaceList.stream().map(Space::getUserId).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 2. 填充信息
        spaceVOList.forEach(spaceVO -> {
            Long userId = spaceVO.getUserId();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            spaceVO.setUserVO(UserVO.objToVO(user));
        });
        spaceVOPage.setRecords(spaceVOList);
        return spaceVOPage;
    }

    @Override
    public QueryWrapper<Space> getQueryWrapper(SpaceQueryRequest queryRequest) {
        QueryWrapper<Space> wrapper = new QueryWrapper<>();

        Long id = queryRequest.getId();
        String spaceName = queryRequest.getSpaceName();
        Integer spaceLevel = queryRequest.getSpaceLevel();
        Long userId = queryRequest.getUserId();
        String sortField = queryRequest.getSortField();
        Boolean isAsc = queryRequest.getIsAsc();

        wrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        wrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        wrapper.eq(ObjUtil.isNotEmpty(spaceLevel), "spaceLevel", spaceLevel);
        wrapper.like(StrUtil.isNotBlank(spaceName), "spaceName", spaceName);
        wrapper.orderBy(StrUtil.isNotBlank(sortField), isAsc, sortField);

        return wrapper;
    }

    /**
     * 根据空间级别填充限额参数
     * @param space
     */
    @Override
    public void fillSpaceByLevel(Space space) {
        // 根据空间级别，自动填充限额
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(space.getSpaceLevel());
        if (spaceLevelEnum == null){
            spaceLevelEnum = SpaceLevelEnum.COMMON; // 设置默认级别
        }
        if (spaceLevelEnum != null) {
            long maxSize = spaceLevelEnum.getMaxSize();
            if (space.getMaxSize() == null) {
                space.setMaxSize(maxSize);
            }
            long maxCount = spaceLevelEnum.getMaxCount();
            if (space.getMaxCount() == null) {
                space.setMaxCount(maxCount);
            }
        }
    }

    /**
     * 校验ID，判断数据是否存在，权限校验
     *
     * @param id
     */
    @Override
    public void checkIdAuthWithExists(Long id, User loginUser) {
        // 数据校验
        ThrowUtils.throwIf(id <= 0 || ObjUtil.isEmpty(id), ErrorCode.PARAMS_ERROR);
        // 判空
        Space space = this.getById(id);
        ThrowUtils.throwIf(ObjUtil.isNull(space), ErrorCode.NOT_FOUND_ERROR);
        // 权限校验 (只空间创建者才有权限)
        if (!space.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间权限");
        }
    }

    @Override
    public void validSpace(Space space, boolean add) {
        ThrowUtils.throwIf(space == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        String spaceName = space.getSpaceName();
        Integer spaceLevel = space.getSpaceLevel();
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
        // 要创建
        if (add) {
            if (StrUtil.isBlank(spaceName)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间名称不能为空");
            }
            if (spaceLevel == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别不能为空");
            }
        }
        // 修改数据时，如果要改空间级别
        if (spaceLevel != null && spaceLevelEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别不存在");
        }
        if (StrUtil.isNotBlank(spaceName) && spaceName.length() > 30) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间名称过长");
        }
    }

}




